package com.xunk.scene.handler.delay;

import com.xunk.common.core.utils.SpringUtils;
import com.xunk.scene.threadpool.ThreadPools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.concurrent.DelayQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @ProjectName: HIM
 * @Package: com.xunk.scene.handler.delay
 * @ClassName: DelayTaskQueueDaemonThread
 * @Author: luanzhiwei
 * @Description: 延时任务守护线程
 * @Date: 2021/5/18 14:58
 * @Version: 1.0
 */
@Slf4j
@Component
public class DelayTaskQueueDaemonThread implements ApplicationRunner {

    private DelayTaskQueueDaemonThread() {
        //私有无参构造
    }

    /**
     * Callback used to run the bean.
     *
     * @param args incoming application arguments
     * @throws Exception on error
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        this.init();
    }

    public static DelayTaskQueueDaemonThread getInstance() {
        return SpringUtils.getBean(DelayTaskQueueDaemonThread.class);
    }

    /**
     * 守护线程
     */
    private Thread daemonThread;

    /**
     * 初始化守护线程
     * 守护线程只有在存在用户线程时才不会被销毁，测试时需要有用户线程等待全部延时任务执行完毕
     */
    public void init() {
        log.info("延时队列，开始初始化守护线程");
        daemonThread = new Thread(() -> execute());
        daemonThread.setName("DelayTask Queue Daemon Thread");
        daemonThread.setDaemon(true);
        daemonThread.start();
        log.info("延时队列，初始化守护线程完成");
    }

    /**
     * 执行任务
     */
    private void execute() {
        while (true) {
            try {
                //从延迟队列中取值,如果没有对象过期则队列一直等待，
                DelayTask t1 = t.take();
                if (t1 != null) {
                    Runnable task = t1.getTask();
                    if (task == null) {
                        continue;
                    }
                    ThreadPools.executor.execute(task);
                }
/*                //让出一会
                Thread.sleep(10);
            } catch (InterruptedException e) {
                log.info("延迟队列守护线程睡眠异常，不处理");*/
            } catch (Exception e) {
                //如果出现不可预期异常，停止死循环
                e.printStackTrace();
                break;
            }
        }
    }

    /**
     * 创建一个最初为空的新 DelayQueue
     */
    private DelayQueue<DelayTask> t = new DelayQueue<>();

    /**
     * @param time     延迟时间
     * @param timeUnit 延迟时间单位
     * @param task     任务
     */
    public void put(long time, TimeUnit timeUnit, Runnable task) {
        //转换成毫秒
        final long millis = TimeUnit.MILLISECONDS.convert(time, timeUnit);
        //创建一个任务
        DelayTask k = new DelayTask(millis, task);
        //将任务放在延迟的队列中
        t.put(k);
    }

    /**
     * 移除延时任务
     *
     * @param task
     */
    public boolean endTask(DelayTask<Runnable> task) {
        return t.remove(task);
    }

}
